/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tpgen.grammar;

import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 *
 * @author shanki
 */
public abstract class Grammar {
    public abstract Symbol getStartSymbol();
    public abstract List<Symbol> getVariableTypes();
    
    private Random rg       = new Random(new Date().getTime());
    
    public Variables generateVars(String prefix, int maxVarsPerType) {
        Variables vars  = new Variables();
        
        
        int index = 0;
        
        for (Symbol type : getVariableTypes()) {
            int number = rg.nextInt(maxVarsPerType-1)+1;
            
            for (int i = 0; i < number; ++i) {
                vars.add(new Variable(prefix + index, type));
                ++index;
            }
        }
        
        return vars;
    }    
    
//    public Node generateExpression(Variables vars) {
//
//        Context context     = new Context(rg, vars);
//        
//        Stack<Node> stack   = new Stack<Node>();
//        Node startNode      = new Node(getStartSymbol(), context);
//        stack.push(startNode);
//        
//        while(stack.isEmpty() == false) {
//            Node actual     = stack.pop();
//            Symbol aSymbol  = actual.getSymbol();
//           
//            int index       = 0;
//            
//            for(Symbol child : aSymbol.expand(context)) {
//                Node cNode  = new Node(child);
//                actual.add(cNode);
//                
//                stack.insertElementAt(cNode, index);
//                ++index;
//            }
//        }
//        
//        return startNode;
//    }
    
    public Node generateExpression(Variables vars) {

        Context context     = new Context(rg, vars);
        Node startNode      = new Node(getStartSymbol(), context);
        startNode.expand();
        
        return startNode;
    }    
    
    public NonTerminal nt(String name, Symbol symbol) {
        return new NonTerminal(name, symbol);
    }
    
    public Symbol seq(Symbol... symbols) {
        return new Sequence(symbols);
    }
    
    public Symbol rep(Symbol symbol, boolean emptyAllowed, double prob) {
        return new Repeat(symbol, emptyAllowed, prob);
    }
    
    public Symbol opt(Symbol symbol, double prob) {
        return new Optional(symbol, prob);
    }

    public Symbol list(Symbol symbol, Symbol delimiter, double prob) {
        return seq(symbol, rep(seq(delimiter, symbol), true, prob));
    }

    public Symbol listMin2(Symbol symbol, Symbol delimiter, double prob) {
        return seq(symbol, rep(seq(delimiter, symbol), false, prob));
    }
    
}